package com.common.util;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.log4j.Logger;
import org.springframework.util.CollectionUtils;

import com.alibaba.fastjson.JSON;
import com.busines.po.StudentPo;
import com.common.util.redis.RedisLock;
import com.common.util.redis.Rock;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.Transaction;
import redis.clients.jedis.exceptions.JedisConnectionException;

/**
 * redis客户端
 * @ClassName ALiRedisClient
 */
public class RedisClient {

	protected final Logger log = Logger.getLogger(getClass());

	private Integer maxIdle; // 最大空闲连接数
	private Integer maxTotal;// 最大连接数
	private Boolean testOnBorrow;
	private Boolean testOnReturn;
	private String host;// 地址(ip或域名)
	private String password;// 密码
	private Integer port;// 端口
	private Integer dbNo;// 数据库编号
	private Integer timeout;
	private JedisPool pool;// 读写取数据用到的连接池

	//redis 锁超时时间 过期时间
	private Long locktimeout;
	private Integer lockexpire;
	
	public RedisClient() {
	}

	/**
	 * 初始化sentinel池核shardPool池
	 */
	public void initialShardedPool() {
		JedisPoolConfig config = new JedisPoolConfig();
		// 最大空闲连接数, 应用自己评估，不要超过ApsaraDB for Redis每个实例最大的连接数
		config.setMaxIdle(maxIdle);
		// 最大连接数, 应用自己评估，不要超过ApsaraDB for Redis每个实例最大的连接数
		config.setMaxTotal(maxTotal);
		config.setTestOnBorrow(testOnBorrow);
		config.setTestOnReturn(testOnReturn);
		pool = new JedisPool(config, host, port, timeout, password);
	}

	/**
	 * 获取redis value (String)
	 * 
	 * @param key
	 * @return
	 */
	public String get(String key) {
		String value = null;
		Jedis jedis = null;
		try {
			jedis = pool.getResource();
			jedis.select(dbNo);
			value = jedis.get(key);
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}

		return value;
	}

	public String incr(String key) {
		String value = null;
		Jedis jedis = null;
		try {
			jedis = pool.getResource();
			jedis.select(dbNo);
			value = jedis.incr(key).toString();
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}

		return value;

	}
	
	public String incrBy(String key,long startNum) {
		String value = null;
		Jedis jedis = null;
		try {
			jedis = pool.getResource();
			jedis.select(dbNo);
			value = jedis.incrBy(key, startNum).toString();
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}

		return value;

	}

	/**
	 * 通过key删除
	 * 
	 * @param key
	 */
	public void del(String key) {
		Jedis jedis = null;
		try {
			jedis = pool.getResource();
			jedis.select(dbNo);
			jedis.del(key);
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}

	}

	/**
	 * 添加key value 并且设置存活时间
	 * 
	 * @param key
	 * @param value
	 * @param liveTime
	 */
	public void set(String key, String value, int liveTime) {
		Jedis jedis = null;
		Transaction tx = null;
		try {
			jedis = pool.getResource();
			jedis.select(dbNo);
			tx = jedis.multi();
			tx.set(key, value);
			tx.expire(key, liveTime);
			tx.exec();
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}

	}

	/**
	 * 添加key value
	 * 
	 * @param key
	 * @param value
	 */
	public void set(String key, String value) {
		Jedis jedis = null;
		Transaction tx = null;
		try {
			jedis = pool.getResource();
			jedis.select(dbNo);
			tx = jedis.multi();
			tx.set(key, value);
			tx.exec();
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}

	}

	/**
	 * 通过正则匹配keys
	 * 
	 * @param pattern
	 * @return
	 */
	public Set<String> keys(String pattern) {
		Jedis jedis = null;
		Set<String> set = null;
		try {
			jedis = pool.getResource();
			jedis.select(dbNo);
			set = jedis.keys(pattern);
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}

		return set;

	}

	/**
	 * 检查key是否已经存在
	 * 
	 * @param key
	 * @return
	 */
	public boolean exists(String key) throws Exception {
		Jedis jedis = null;
		boolean flag = true;
		try {
			jedis = pool.getResource();
			jedis.select(dbNo);
			flag = jedis.exists(key);
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}

		return flag;

	}

	/**
	 * 清空redis 所有数据
	 * 
	 * @return
	 */
	public String flushDB() {
		String value = null;
		Jedis jedis = null;
		try {
			jedis = pool.getResource();
			jedis.select(dbNo);
			value = jedis.flushDB();
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}

		return value;

	}

	/**
	 * 查看redis里有多少数据
	 */
	public long dbSize() {
		Jedis jedis = null;
		long dbSize = 0;
		try {
			jedis = pool.getResource();
			jedis.select(dbNo);
			dbSize = jedis.dbSize();
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}

		return dbSize;

	}

	/**
	 * 向redis中添加list对象
	 * 
	 * @param key
	 * @param list
	 * @param expireSeconds
	 */
	public void setList(String key, List<String> list, int expireSeconds) {
		Jedis jedis = null;
		Transaction tx = null;
		try {
			jedis = pool.getResource();
			jedis.select(dbNo);
			tx = jedis.multi();
			tx.del(key);
			tx.rpush(key, (String[]) list.toArray(new String[list.size()]));
			if (expireSeconds != -1) {
				tx.expire(key, expireSeconds);
			}
			tx.exec();
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}

	}

	/**
	 * 向list中添加元素
	 * 
	 * @param key
	 * @param memberValue
	 */
	public void addListMember(String key, String memberValue) {
		Jedis jedis = null;
		try {
			jedis = pool.getResource();
			jedis.select(dbNo);
			jedis.rpush(key, memberValue);
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}

	}

	/**
	 * 获取list对象
	 * 
	 * @param key
	 * @return
	 */
	public List<String> getList(String key) {

		Jedis jedis = null;
		List<String> values = null;
		try {
			jedis = pool.getResource();
			jedis.select(dbNo);
			values = jedis.lrange(key, 0, -1);
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}

		return values;

	}

	/**
	 * 向list中添加元素
	 * 
	 * @param key
	 * @param memberValue
	 */
	public void addListMemberFromHeadWithFixSize(String key, String memberValue, int fixSize) {
		Jedis jedis = null;
		try {
			jedis = pool.getResource();
			jedis.select(dbNo);
			jedis.lpush(key, memberValue);
			jedis.ltrim(key, 0, fixSize - 1);
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}

	}

	/**
	 * 向redis中添加set对象
	 * 
	 * @param key
	 * @param set
	 * @param expireSeconds
	 */
	public void setSet(String key, Set<String> set, int expireSeconds) {
		Jedis jedis = null;
		Transaction tx = null;
		try {
			jedis = pool.getResource();
			jedis.select(dbNo);
			tx = jedis.multi();
			tx.del(key);
			tx.sadd(key, (String[]) set.toArray(new String[set.size()]));
			if (expireSeconds != -1) {
				tx.expire(key, expireSeconds);
			}
			tx.exec();
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}

	}

	/**
	 * 向map中添加一个元素
	 * 
	 * @param key
	 * @param memberValue
	 */
	public void addSetMember(String key, String memberValue) {
		Jedis jedis = null;
		try {
			jedis = pool.getResource();
			jedis.select(dbNo);
			jedis.sadd(key, memberValue);
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}

	}

	/**
	 * 从map中移除指定元素
	 * 
	 * @param key
	 * @param memberValue
	 */
	public void removeSetMember(String key, String memberValue) {
		Jedis jedis = null;
		try {
			jedis = pool.getResource();
			jedis.select(dbNo);
			jedis.srem(key, memberValue);
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}

	}

	/**
	 * 判断set中是否存在值memberValue
	 * 
	 * @param key
	 * @param memberValue
	 * @return
	 */
	public boolean isContainMemberOfSet(String key, String memberValue) {
		Jedis jedis = null;
		boolean isExist = false;
		try {
			jedis = pool.getResource();
			jedis.select(dbNo);
			isExist = jedis.sismember(key, memberValue);
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}

		return isExist;
	}

	/**
	 * 获取set对象
	 * 
	 * @param key
	 * @return
	 */
	public Set<String> getSet(String key) {

		Jedis jedis = null;
		Set<String> value = null;
		try {
			jedis = pool.getResource();
			jedis.select(dbNo);
			value = jedis.smembers(key);
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}

		return value;
	}

	/**
	 * 向redis中新增map
	 * 
	 * @param key
	 * @param map
	 * @param expireSeconds
	 */
	public void setMap(String key, Map<String, String> map, int expireSeconds) {
		Jedis jedis = null;
		Transaction tx = null;
		try {
			jedis = pool.getResource();
			jedis.select(dbNo);
			tx = jedis.multi();
			tx.hmset(key, map);
			if (expireSeconds != -1) {
				tx.expire(key, expireSeconds);
			}
			tx.exec();
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}

	}

	/**
	 * 向map中添加元素
	 * 
	 * @param key
	 * @param mapKey
	 * @param mapValue
	 */
	public void addMapMember(String key, String mapKey, String mapValue) {
		Jedis jedis = null;
		try {
			jedis = pool.getResource();
			jedis.select(dbNo);
			Map<String, String> sourceMap = jedis.hgetAll(key);
			sourceMap.put(mapKey, mapValue);
			jedis.hmset(key, sourceMap);
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}

	}

	/**
	 * 获取map的所有key列表
	 * 
	 * @param key
	 * @return
	 */
	public Set<String> getMapAllKeys(String key) {
		Set<String> value = null;
		Jedis jedis = null;
		try {
			jedis = pool.getResource();
			jedis.select(dbNo);
			value = jedis.hkeys(key);
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}

		return value;
	}

	/**
	 * 获取map的所有值列表
	 * 
	 * @param key
	 * @return
	 */
	public List<String> getMapAllValues(String key) {
		List<String> value = null;
		Jedis jedis = null;
		try {
			jedis = pool.getResource();
			jedis.select(dbNo);
			value = jedis.hvals(key);
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}

		return value;

	}

	/**
	 * 获取map对象
	 * 
	 * @param key
	 * @return
	 */
	public Map<String, String> getMap(String key) {
		Map<String, String> value = new HashMap<String, String>();
		Jedis jedis = null;
		try {
			jedis = pool.getResource();
			jedis.select(dbNo);
			value = jedis.hgetAll(key);
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}

		return value;
	}

	/**
	 * 删除map的指定元素
	 * 
	 * @param key
	 * @param mapKey
	 */
	public void deleteMapMember(String key, String mapKey) {
		Jedis jedis = null;
		try {
			jedis = pool.getResource();
			jedis.select(dbNo);
			jedis.hdel(key, mapKey);
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}

	}

	/**
	 * 根据key和map的key获取指定的map值
	 * 
	 * @param key
	 * @param mapKey
	 * @return
	 */
	public String getMapValue(String key, String mapKey) {
		Jedis jedis = null;
		String value = null;
		try {
			jedis = pool.getResource();
			jedis.select(dbNo);
			value = jedis.hget(key, mapKey);
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}

		return value;
	}

	/**
	 * setExpire(这里用一句话描述这个方法的作用) 设置key的超时时间
	 * 
	 * @param @param
	 *            token
	 * @param @param
	 *            expireSeconds
	 * @return void
	 * @Exception 异常对象
	 */
	public void setExpire(String key, int liveTime) {

		Jedis jedis = null;
		Transaction tx = null;
		try {
			jedis = pool.getResource();
			jedis.select(dbNo);
			tx = jedis.multi();
			tx.expire(key, liveTime);
			tx.exec();
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}

	}

	/**
	 * delKeys(这里用一句话描述这个方法的作用) 批量删除
	 * 
	 * @param @param
	 *            keys
	 * @return void
	 * @Exception 异常对象
	 */
	public void delKeys(Set<String> keys) {

		Jedis jedis = null;
		try {
			jedis = pool.getResource();
			jedis.select(dbNo);
			jedis.del((String[]) keys.toArray(new String[keys.size()]));
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}

	}

	/**
	 * 更新map键值
	 * 
	 * @param key
	 * @param mapkey
	 * @param value
	 */
	public void setHashMapValue(String key, String mapkey, String value) {
		Jedis jedis = null;
		try {
			jedis = pool.getResource();
			jedis.select(dbNo);
			jedis.hset(key, mapkey, value);
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}

	}

	/**
	 * 添加队列元素,左进右出规则
	 * 
	 * @param key
	 * @param value
	 */
	public void setListValue(String key, String value, int time) {
		Jedis jedis = null;
		try {
			jedis = pool.getResource();
			jedis.select(dbNo);
			jedis.lpush(key, value);
			if (time != -1) {
				jedis.expire(key, time);
			}
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}

	}

	/**
	 * 删除队列元素，左进右出规则
	 * 
	 * @param key
	 * @param value
	 */
	public void delListValue(String key) {
		Jedis jedis = null;
		try {
			jedis = pool.getResource();
			jedis.select(dbNo);
			jedis.rpop(key);
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}
	}

	/**
	 * 设置订单对象
	 * 
	 * @param key
	 * @param object
	 */
	public void setMepOrderCache(String key, Map<String, String> object) {
		Jedis instance = null;
		boolean borrowOrOprSuccess = true;
		try {
			instance = pool.getResource();
			instance.select(dbNo);
			instance.hmset(key, object);
		} catch (JedisConnectionException e) {
			borrowOrOprSuccess = false;
			if (instance != null) {
				instance.close();
			}
		} finally {
			if (borrowOrOprSuccess) {
				if (instance != null) {
					instance.close();
				}
			}
		}

	}

	/**
	 * 订单map对象获取 @Title: getMepOrderCache @Description:
	 * TODO(这里用一句话描述这个方法的作用) @author feilun @param @param
	 * key @param @return @return Map<String,String> @throws
	 */
	public Map<String, String> getMepOrderCache(String key) {
		Jedis instance = null;
		boolean borrowOrOprSuccess = true;
		try {
			instance = pool.getResource();
			instance.select(dbNo);
			Map<String, String> map = instance.hgetAll(key);
			return map;
		} catch (JedisConnectionException e) {
			borrowOrOprSuccess = false;
			if (instance != null) {
				instance.close();
			}
		} finally {
			if (borrowOrOprSuccess) {
				if (null != instance) {
					instance.close();
				}
			}
		}
		return null;
	}
	//TODO
	public Boolean setObjectCache(String str ,Object obj){
		if(null == obj){
			return false;
		}
		try {
			String o = JSON.toJSONString(obj);
			this.set(str, o);
		} catch (Exception e) {
			log.error("对象转字符串失败");
			e.printStackTrace();
			return false;
		}
		return true;
	}
	//TODO
	public <T> T getObjectCache(String key,Class<T> clazz){
		
		try {
			String str = this.get(key);
			if(null !=str){
				return JSON.parseObject(str, clazz);
			}
		} catch (Exception e) {
			log.error("获取key" + key);
            log.error("转换字符串为"+clazz+"对象错误", e);
		}
		
		return null;
	}
	//TODO 传入对象转一把map丢入redis
	public Boolean setObjectCacheHash(String key,Object obj,int expiretime){
		if(null==obj){
			return false;
		}
		try {
			Map<String,String> map = BeanUtilsExtends.transBean2MapStr(obj);
			this.setMap(key, map, expiretime);
		} catch (Exception e) {
			log.error("obj转map失败",e);
			return false;
		}
		return true;
	}
	//TODO 从缓存取出map 转成对象
	public <T> T getObjectCacheHsha(String key,Class<T> clazz){
			try {
				Map<String,String> map = this.getMap(key);
				T obj = clazz.newInstance();
				if(!CollectionUtils.isEmpty(map)){
					BeanUtilsExtends.transMapStr2Bean(map, obj);
					return obj;
				}
			} catch (Exception e) {
				 log.error("获取key" + key);
		         log.error("转换字符串为"+clazz+"对象错误", e);
			}
			return null;
	}
	//TODO
	public <T extends Rock> T getStudentPoCacheByLock(String key,Class<T> clazz){
		Jedis instance = null;
		T obj = null;
		try {
			obj = clazz.newInstance();
			instance = pool.getResource();
			instance.select(dbNo);
			RedisLock redislock = new RedisLock(key);
			if(redislock.lock(locktimeout, lockexpire, pool,dbNo)){
				Map<String, String> map = instance.hgetAll(key);
				if(!CollectionUtils.isEmpty(map)){
					BeanUtilsExtends.transMapStr2Bean(map, obj);
					obj.setRlock(redislock);
				}
			}
		} catch (Exception e) {
			log.error(e);
		}finally{
			if(instance!=null){
				instance.close();
			}
		}
		return obj;
	}
	//TODO
	public void unlock(RedisLock lock){
		if(null != lock){
		lock.unlock(pool,dbNo);
		}
	}

	public Integer getMaxIdle() {
		return maxIdle;
	}

	public void setMaxIdle(Integer maxIdle) {
		this.maxIdle = maxIdle;
	}

	public Integer getMaxTotal() {
		return maxTotal;
	}

	public void setMaxTotal(Integer maxTotal) {
		this.maxTotal = maxTotal;
	}

	public Boolean getTestOnBorrow() {
		return testOnBorrow;
	}

	public void setTestOnBorrow(Boolean testOnBorrow) {
		this.testOnBorrow = testOnBorrow;
	}

	public Boolean getTestOnReturn() {
		return testOnReturn;
	}

	public void setTestOnReturn(Boolean testOnReturn) {
		this.testOnReturn = testOnReturn;
	}

	public String getHost() {
		return host;
	}

	public void setHost(String host) {
		this.host = host;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public Integer getPort() {
		return port;
	}

	public void setPort(Integer port) {
		this.port = port;
	}

	public JedisPool getPool() {
		return pool;
	}

	public void setPool(JedisPool pool) {
		this.pool = pool;
	}

	public Integer getDbNo() {
		return dbNo;
	}

	public void setDbNo(Integer dbNo) {
		this.dbNo = dbNo;
	}

	public Integer getTimeout() {
		return timeout;
	}

	public void setTimeout(Integer timeout) {
		this.timeout = timeout;
	}

	public Long getLocktimeout() {
		return locktimeout;
	}

	public void setLocktimeout(Long locktimeout) {
		this.locktimeout = locktimeout;
	}

	public Integer getLockexpire() {
		return lockexpire;
	}

	public void setLockexpire(Integer lockexpire) {
		this.lockexpire = lockexpire;
	}

}
